﻿using Helpers.Common;
using System;
using System.Collections.Generic;
using log4net;

namespace Helpers.Log
{
    /// <summary>
    /// Handles the log of a method with parameters, begin message, end messages and other stuff.
    /// </summary>
    public class TransactionLogger
    {
        #region Properties

        /// <summary>
        /// A list of message of the type begin/end.
        /// </summary>
        private Stack<string> BeginEndMessagesList = new Stack<string>();
        /// <summary>
        /// The start message to be used on BeginLog methods.
        /// </summary>
        public string LogBeginMessage = TransactionLogger.DEFAULT_LOG_BEGIN_MESSAGE;
        /// <summary>
        /// The start message to be used on EndLog methods.
        /// </summary>
        public string LogEndMessage = TransactionLogger.DEFAULT_LOG_END_MESSAGE;
        /// <summary>
        /// A <see cref="log4net.ILog"/> instance for log.
        /// </summary>
        public ILog Logger;
        /// <summary>
        /// Indicates if the method ID variable must be logged on the method event log.
        /// </summary>
        public bool LogID = true;
        /// <summary>
        /// A unique id to be logged (or not) on the method event log.
        /// </summary>
        public int ID = ++TransactionLogger.count;
        /// <summary>
        /// The name of the method to be logged.
        /// </summary>
        public string MethodName = "";
        /// <summary>
        /// The list of parameters of the method to be logged.
        /// </summary>
        public Dictionary<string, object> ParametersCollection = new Dictionary<string, object>();
        /// <summary>
        /// A user name to be logged indicating who execute the method logged.
        /// </summary>
        public string UserName = "";

        #endregion

        #region Statis Properties

        private static int count = -1;

        /// <summary>
        /// The default value for the parameter "logParameters".
        /// </summary>
        private const bool DEFAULT_LOG_PARAMETERS = false;
        /// <summary>
        /// The default value for the parameter "logParameters" on the "LogBegin" methods.
        /// </summary>
        private const bool DEFAULT_LOG_PARAMETERS_BEGIN = true;

        /// <summary>
        /// The default value of the strand "LogBeginMessage".
        /// </summary>
        private const string DEFAULT_LOG_BEGIN_MESSAGE = "Begin";
        /// <summary>
        /// The default value of the strand "LogEndMessage".
        /// </summary>
        private const string DEFAULT_LOG_END_MESSAGE = "End";

        /// <summary>
        /// Message for the end of the transaction.
        /// </summary>
        private const string MESSAGE_TRANS_END = "";
        /// <summary>
        /// Message for the start of the transaction.
        /// </summary>
        private const string MESSAGE_TRANS_START = "";
        /// <summary>
        /// Place holder to be replaced by the transaction's data.
        /// </summary>
        private const string MESSAGE_DATA_REPLACE = "**DATA**";
        /// <summary>
        /// Message of error.
        /// </summary>
        private const string MESSAGE_ERROR = "Error";

        /// <summary>
        /// Message template for the transaction's exception info.
        /// </summary>
        private const string MESSAGE_EXCEPTION_CONTAINER = "[" + TransactionLogger.MESSAGE_DATA_REPLACE + "]";
        /// <summary>
        /// Message template for the transaction's parameters info.
        /// </summary>
        private const string MESSAGE_PARAMS_CONTAINER = "(" + TransactionLogger.MESSAGE_DATA_REPLACE + ")";
        /// <summary>
        /// Message template for the transaction's user info.
        /// </summary>
        private const string MESSAGE_USER_CONTAINER = "Request by:[" + TransactionLogger.MESSAGE_DATA_REPLACE + "]";

        #endregion

        /// <summary>
        /// Initializes a new instance of the <typeparamref name="TransactionLogger"/> class.
        /// </summary>
        public TransactionLogger() : this(null, "")
        {
        }
        /// <summary>
        /// Initializes a new instance of the <typeparamref name="TransactionLogger"/> class.
        /// </summary>
        /// <param name="logger">The <see cref="log4net.ILog"/> instance for log.</param>
        public TransactionLogger(ILog logger) : this(logger, "")
        {
        }
        /// <summary>
        /// Initializes a new instance of the <typeparamref name="TransactionLogger"/> class.
        /// </summary>
        /// <param name="logger">The <see cref="log4net.ILog"/> instance for log.</param>
        /// <param name="methodName">The name of the method to be logged.</param>
        public TransactionLogger(ILog logger, string methodName)
        {
            this.Logger = logger;
            this.MethodName = methodName;
        }

        #region Methods

        /// <summary>
        /// Gets a empty space string if the message specified is not an empty string.
        /// </summary>
        /// <param name="message">The message to be evaluated.</param>
        /// <returns>An empty space string if the message specified is not an empty string.</returns>
        protected virtual string GetSpaceIfNotEmpty(string message)
        {
            return (message.Length != 0)
                            ? " "
                            : "";
        }

        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        public virtual void Log()
        {
            this.Log("", this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void Log(string logMessage)
        {
            this.Log(logMessage, this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void Log(string logMessage, string startMessage)
        {
            this.Log(logMessage, this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void Log(string logMessage, string startMessage, string endMessage)
        {
            this.Log(logMessage, this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage, endMessage);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        public virtual void Log(string logMessage, ILog logger)
        {
            this.Log(logMessage, logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void Log(string logMessage, ILog logger, string startMessage)
        {
            this.Log(logMessage, logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void Log(string logMessage, ILog logger, string startMessage, string endMessage)
        {
            this.Log(logMessage, logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage, endMessage);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        public virtual void Log(string logMessage, bool logParameters)
        {
            this.Log(logMessage, this.Logger, logParameters, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void Log(string logMessage, bool logParameters, string startMessage)
        {
            this.Log(logMessage, this.Logger, logParameters, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void Log(string logMessage, bool logParameters, string startMessage, string endMessage)
        {
            this.Log(logMessage, this.Logger, logParameters, startMessage, endMessage);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        public virtual void Log(string logMessage, ILog logger, bool logParameters)
        {
            this.Log(logMessage, logger, logParameters, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void Log(string logMessage, ILog logger, bool logParameters, string startMessage)
        {
            this.Log(logMessage, logger, logParameters, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the method and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void Log(string logMessage, ILog logger, bool logParameters, string startMessage, string endMessage)
        {
            ILog previousLogger = this.Logger;
            this.Logger = logger;
                string message = "";

            message += startMessage;

            message += this.GetSpaceIfNotEmpty(message) + this.MethodName;

            if (this.LogID == true)
            {
                message += this.GetSpaceIfNotEmpty(message) + this.ID.ToString();
            }

            if (logMessage.Trim().Length != 0)
            {
                message += this.GetSpaceIfNotEmpty(message) + logMessage;
            }

            if ((logParameters == true) && (this.ParametersCollection.Count > 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_PARAMS_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.ParametersCollection.ToLog()
                        );
            }

            if ((this.UserName != null) && (this.UserName.Length != 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_USER_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.UserName
                        );
            }

            this.Logger.Debug(message);

            this.Logger = previousLogger;
        }
        /// <summary>
        /// Logs the method, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        public virtual void Log(Exception exception)
        {
            this.Log(exception, this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the method, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void Log(Exception exception, string startMessage)
        {
            this.Log(exception, this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage);
        }
        /// <summary>
        /// Logs the method, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        public virtual void Log(Exception exception, ILog logger)
        {
            this.Log(exception, logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the method, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void Log(Exception exception, ILog logger, string startMessage)
        {
            this.Log(exception, logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage);
        }
        /// <summary>
        /// Logs the method, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        public virtual void Log(Exception exception, bool logParameters)
        {
            this.Log(exception, this.Logger, logParameters, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the method, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void Log(Exception exception, bool logParameters, string startMessage)
        {
            this.Log(exception, this.Logger, logParameters, startMessage);
        }
        /// <summary>
        /// Logs the method, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        public virtual void Log(Exception exception, ILog logger, bool logParameters)
        {
            this.Log(exception, this.Logger, logParameters, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the method, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void Log(Exception exception, ILog logger, bool logParameters, string startMessage)
        {
            ILog previousLogger = this.Logger;
            this.Logger = logger;
            string parametersForLog = this.ParametersCollection.ToLog();
            string message = "";

            message += startMessage;

            message += this.GetSpaceIfNotEmpty(message) + this.MethodName;

            if (this.LogID == true)
            {
                message += this.GetSpaceIfNotEmpty(message) + this.ID.ToString();
            }

            message += this.GetSpaceIfNotEmpty(message) + TransactionLogger.MESSAGE_ERROR;

            if ((logParameters == true) && (this.ParametersCollection.Count > 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_PARAMS_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.ParametersCollection.ToLog()
                        );
            }

            message += this.GetSpaceIfNotEmpty(message)
                    + TransactionLogger.MESSAGE_EXCEPTION_CONTAINER.Replace(
                        TransactionLogger.MESSAGE_DATA_REPLACE, exception.Message
                    );

            this.Logger.Debug(message);

            message = "";

            message += this.GetSpaceIfNotEmpty(message) + this.MethodName;

            if (this.LogID == true)
            {
                message += this.GetSpaceIfNotEmpty(message) + this.ID.ToString();
            }

            message += this.GetSpaceIfNotEmpty(message) + TransactionLogger.MESSAGE_ERROR;

            if ((logParameters == true) && (this.ParametersCollection.Count > 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_PARAMS_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.ParametersCollection.ToLog()
                        );
            }

            this.Logger.Error(message, exception);

            this.Logger = previousLogger;
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        public virtual void LogBegin()
        {
            this.LogBegin("", this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS_BEGIN, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void LogBegin(string logMessage)
        {
            this.LogBegin(logMessage, this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS_BEGIN, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void LogBegin(string logMessage, string startMessage)
        {
            this.LogBegin(logMessage, this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS_BEGIN, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void LogBegin(string logMessage, string startMessage, string endMessage)
        {
            this.LogBegin(logMessage, this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS_BEGIN, startMessage, endMessage);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        public virtual void LogBegin(string logMessage, ILog logger)
        {
            this.LogBegin(logMessage, logger, TransactionLogger.DEFAULT_LOG_PARAMETERS_BEGIN, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void LogBegin(string logMessage, ILog logger, string startMessage)
        {
            this.LogBegin(logMessage, logger, TransactionLogger.DEFAULT_LOG_PARAMETERS_BEGIN, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void LogBegin(string logMessage, ILog logger, string startMessage, string endMessage)
        {
            this.LogBegin(logMessage, logger, TransactionLogger.DEFAULT_LOG_PARAMETERS_BEGIN, startMessage, endMessage);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        public virtual void LogBegin(string logMessage, bool logParameters)
        {
            this.LogBegin(logMessage, this.Logger, logParameters, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void LogBegin(string logMessage, bool logParameters, string startMessage)
        {
            this.LogBegin(logMessage, this.Logger, logParameters, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void LogBegin(string logMessage, bool logParameters, string startMessage, string endMessage)
        {
            this.LogBegin(logMessage, this.Logger, logParameters, startMessage, endMessage);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        public virtual void LogBegin(string logMessage, ILog logger, bool logParameters)
        {
            this.LogBegin(logMessage, logger, logParameters, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void LogBegin(string logMessage, ILog logger, bool logParameters, string startMessage)
        {
            this.LogBegin(logMessage, logger, logParameters, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the begin of the method to be logged and its data.
        /// </summary>
        /// <param name="logMessage">An extra message to be logged.</param>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void LogBegin(string logMessage, ILog logger, bool logParameters, string startMessage, string endMessage)
        {
            ILog previousLogger = this.Logger;
            this.Logger = logger;
            this.BeginEndMessagesList.Push(logMessage);
            string message = "";

            message += startMessage;

            message += this.GetSpaceIfNotEmpty(message) + this.LogBeginMessage + " " + this.MethodName;

            if (this.LogID == true)
            {
                message += this.GetSpaceIfNotEmpty(message) + this.ID.ToString();
            }

            if (logMessage.Trim().Length != 0)
            {
                message += this.GetSpaceIfNotEmpty(message) + logMessage;
            }

            if ((logParameters == true) && (this.ParametersCollection.Count > 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_PARAMS_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.ParametersCollection.ToLog()
                        );
            }

            if ((this.UserName != null) && (this.UserName.Length != 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_USER_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.UserName
                        );
            }

            message += this.GetSpaceIfNotEmpty(message) + endMessage;

            this.Logger.Debug(message);

            this.Logger = previousLogger;
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        public virtual void LogEnd()
        {
            this.LogEnd(this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, TransactionLogger.MESSAGE_TRANS_START);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void LogEnd(string startMessage)
        {
            this.LogEnd(this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void LogEnd(string startMessage, string endMessage)
        {
            this.LogEnd(this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage, endMessage);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        public virtual void LogEnd(ILog logger)
        {
            this.LogEnd(logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, TransactionLogger.MESSAGE_TRANS_START, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void LogEnd(ILog logger, string startMessage)
        {
            this.LogEnd(logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void LogEnd(ILog logger, string startMessage, string endMessage)
        {
            this.LogEnd(logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, startMessage, endMessage);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        public virtual void LogEnd(bool logParameters)
        {
            this.LogEnd(this.Logger, logParameters, TransactionLogger.MESSAGE_TRANS_START, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void LogEnd(bool logParameters, string startMessage)
        {
            this.LogEnd(this.Logger, logParameters, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void LogEnd(bool logParameters, string startMessage, string endMessage)
        {
            this.LogEnd(this.Logger, logParameters, startMessage, endMessage);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        public virtual void LogEnd(ILog logger, bool logParameters)
        {
            this.LogEnd(logger, logParameters, TransactionLogger.MESSAGE_TRANS_START, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        public virtual void LogEnd(ILog logger, bool logParameters, string startMessage)
        {
            this.LogEnd(logger, logParameters, startMessage, TransactionLogger.MESSAGE_TRANS_END);
        }
        /// <summary>
        /// Logs the end of the method to be logged and its data.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="startMessage">A message to be logged and the start of the main message.</param>
        /// <param name="endMessage">A message to be logged and the end of the main message.</param>
        public virtual void LogEnd(ILog logger, bool logParameters, string startMessage, string endMessage)
        {
            ILog previousLogger = this.Logger;
            this.Logger = logger;
            string logMessage = this.BeginEndMessagesList.Pop();
            string message = "";

            message += startMessage;

            message += this.GetSpaceIfNotEmpty(message) + this.LogEndMessage;

            if (logMessage.Trim().Length != 0)
            {
                message += this.GetSpaceIfNotEmpty(message) + logMessage;
            }

            if (this.LogID == true)
            {
                message += this.GetSpaceIfNotEmpty(message) + this.ID.ToString();
            }

            if ((logParameters == true) && (this.ParametersCollection.Count > 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_PARAMS_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.ParametersCollection.ToLog()
                        );
            }

            if ((this.UserName != null) && (this.UserName.Length != 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_USER_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.UserName
                        );
            }

            message += this.GetSpaceIfNotEmpty(message) + endMessage;

            this.Logger.Debug(message);

            this.Logger = previousLogger;
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        public virtual void LogEnd(Exception ex)
        {
            this.LogEnd(this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, ex, "");
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the exception specified.
        /// </summary>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void LogEnd(Exception ex, string logMessage)
        {
            this.LogEnd(this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, ex, logMessage);
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the exception specified.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="ex">The exception to be logged.</param>
        public virtual void LogEnd(ILog logger, Exception ex)
        {
            this.LogEnd(logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, ex, "");
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the exception specified.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void LogEnd(ILog logger, Exception ex, string logMessage)
        {
            this.LogEnd(logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, ex, logMessage);
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the exception specified.
        /// </summary>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="ex">The exception to be logged.</param>
        public virtual void LogEnd(bool logParameters, Exception ex)
        {
            this.LogEnd(this.Logger, logParameters, ex, "");
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the exception specified.
        /// </summary>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void LogEnd(bool logParameters, Exception ex, string logMessage)
        {
            this.LogEnd(this.Logger, logParameters, ex, logMessage);
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the exception specified.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="ex">The exception to be logged.</param>
        public virtual void LogEnd(ILog logger, bool logParameters, Exception ex)
        {
            this.LogEnd(logger, logParameters, ex, "");
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the exception specified.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="ex">The exception to be logged.</param>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void LogEnd(ILog logger, bool logParameters, Exception ex, string logMessage)
        {
            ILog previousLogger = this.Logger;
            this.Logger = logger;
            string beginEndMessage = this.BeginEndMessagesList.Pop();
            string message = "";

            message += this.LogEndMessage + " " + this.MethodName;
            
            if (this.LogID == true)
            {
                message += this.GetSpaceIfNotEmpty(message) + this.ID.ToString();
            }

            message += this.GetSpaceIfNotEmpty(message) + logMessage;

            message += this.GetSpaceIfNotEmpty(message) + " [Exception: " + ex.Message + "]";

            if (beginEndMessage.Trim().Length != 0)
            {
                message += this.GetSpaceIfNotEmpty(message) + beginEndMessage;
            }

            if ((logParameters == true) && (this.ParametersCollection.Count > 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_PARAMS_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.ParametersCollection.ToLog()
                        );
            }

            if ((this.UserName != null) && (this.UserName.Length != 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_USER_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.UserName
                        );
            }

            this.Logger.Debug(message);

            this.Logger.Error(ex);

            this.Logger = previousLogger;
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the response specified.
        /// </summary>
        /// <param name="response">The response to be logged.</param>
        public virtual void LogEnd<RType>(Response<RType> response)
        {
            this.LogEnd(this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, response, "");
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the response specified.
        /// </summary>
        /// <param name="response">The response to be logged.</param>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void LogEnd<RType>(Response<RType> response, string logMessage)
        {
            this.LogEnd(this.Logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, response, logMessage);
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the response specified.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="response">The response to be logged.</param>
        public virtual void LogEnd<RType>(ILog logger, Response<RType> response)
        {
            this.LogEnd(logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, response, "");
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the response specified.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="response">The response to be logged.</param>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void LogEnd<RType>(ILog logger, Response<RType> response, string logMessage)
        {
            this.LogEnd(logger, TransactionLogger.DEFAULT_LOG_PARAMETERS, response, logMessage);
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the response specified.
        /// </summary>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="response">The response to be logged.</param>
        public virtual void LogEnd<RType>(bool logParameters, Response<RType> response)
        {
            this.LogEnd(this.Logger, logParameters, response, "");
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the response specified.
        /// </summary>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="response">The response to be logged.</param>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void LogEnd<RType>(bool logParameters, Response<RType> response, string logMessage)
        {
            this.LogEnd(this.Logger, logParameters, response, logMessage);
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the response specified.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="response">The response to be logged.</param>
        public virtual void LogEnd<RType>(ILog logger, bool logParameters, Response<RType> response)
        {
            this.LogEnd(logger, logParameters, response, "");
        }
        /// <summary>
        /// Logs the end of the method to be logged, its data and the response specified.
        /// </summary>
        /// <param name="logger">A <see cref="log4net.ILog"/> instance to replace the own logger of the class for an alternative log.</param>
        /// <param name="logParameters">Indicates if the parameters of the method msut be logged.</param>
        /// <param name="response">The response to be logged.</param>
        /// <param name="logMessage">An extra message to be logged.</param>
        public virtual void LogEnd<RType>(ILog logger, bool logParameters, Response<RType> response, string logMessage)
        {
            ILog previousLogger = this.Logger;
            this.Logger = logger;
            string beginEndMessage = this.BeginEndMessagesList.Pop();
            string message = "";

            message += this.LogEndMessage + " " + this.MethodName;

            if (this.LogID == true)
            {
                message += this.GetSpaceIfNotEmpty(message) + this.ID.ToString();
            }

            message += this.GetSpaceIfNotEmpty(message) + logMessage;

            message += this.GetSpaceIfNotEmpty(message)
                    + ((response.Success)
                            ? ""
                            : (response.Exception != null)
                                ? string.Format(" [Response: '{0}', Exception: '{1}'].", response.Message, response.Exception.Message)
                                : string.Format(" [Response: '{0}'].", response.Message))
                    + "]";

            if (beginEndMessage.Trim().Length != 0)
            {
                message += this.GetSpaceIfNotEmpty(message) + beginEndMessage;
            }

            if ((logParameters == true) && (this.ParametersCollection.Count > 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_PARAMS_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.ParametersCollection.ToLog()
                        );
            }

            if ((this.UserName != null) && (this.UserName.Length != 0))
            {
                message += this.GetSpaceIfNotEmpty(message)
                        + TransactionLogger.MESSAGE_USER_CONTAINER.Replace(
                            TransactionLogger.MESSAGE_DATA_REPLACE, this.UserName
                        );
            }

            this.Logger.Debug(message);

            this.Logger = previousLogger;
        }

        #endregion
    }
}